package TXPathFinder;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
*       \class	XMLParser
*	\brief	Parse les réponse du serveur et les réquete à celui-ci
**/
public class XMLParser {

    /**
    *	\brief	Constructeur
    **/
    public XMLParser(){

    }

    /**
    *	\brief	Génére l'arbre XML à parser de la réponse du programme C++
    *   \param source Réponse du serveur C++
    *   \return Le document à parser
    **/
    private Document generateDom(InputSource source)
    {
        Document dom = null;
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

        try
        {
            DocumentBuilder db = dbf.newDocumentBuilder();
            dom = db. parse(source);
        }
        catch(ParserConfigurationException pce)
        {
            // XXX : gérer ça niveau GUI
            pce.printStackTrace();
        }
        catch(SAXException se)
        {
            // XXX : gérer ça niveau GUI
            se.printStackTrace();
        }
        catch(IOException ioe)
        {
            // XXX : gérer ça niveau GUI
            ioe.printStackTrace();
        }
        
        return dom;
    }

    /**
    *	\brief	Récupere une map3D à partir de la réponse du programme C++
    *   \param src Réponse du serveur C++
    *  \return La map 3D
    **/
    public Map3D getMap(InputSource src)
    {
        Document dom = generateDom(src);
        int rowCount;
        int colCount;
        Element elXML = dom.getDocumentElement();
        Map3D map;

        if (!elXML.getTagName().equals("Map"))
        {
            return new Map3D(0,0);
        }

        rowCount = Integer.parseInt(elXML.getAttribute("Height"));
        colCount = Integer.parseInt(elXML.getAttribute("Width"));

        map = new Map3D(rowCount, colCount);

        NodeList row = elXML.getElementsByTagName("Row");

        int l = row.getLength();

        if(row != null && row.getLength() > 0)
        {
            for(int i = 0 ; i < row.getLength(); i++)
            {
                Element el_row = (Element)row.item(i);
                String str_row =  el_row.getTextContent();
                int lenght = str_row.length();
                for(int j = 0; j < lenght ; j++)
                {
                    char carac = str_row.charAt(j);
                    String str_carac = String.valueOf(carac);
                    int value = Integer.parseInt(str_carac);
                    map.setValueMap(i, j, value);
                }
            }
        }
        return map;
    }

    /**
    *	\brief	Récupere la liste des avatars
    *   \param src Réponse du serveur C++
    *  \return La liste des coordonnées
    **/
    public Hashtable<Integer, Coordonnee> getAgents(InputSource src)
    {
        Document dom = generateDom(src);
        int yPos;
        int xPos;
        int id;
        NodeList agents;
        Element elXML = dom.getDocumentElement();
        Hashtable<Integer, Coordonnee> coordinates = new  Hashtable<Integer, Coordonnee>();

        if (!elXML.getTagName().equals("Agents"))
        {
            return coordinates;
        }

        agents = elXML.getElementsByTagName("Agent");

        if(agents != null && agents.getLength() > 0)
        {
            for(int i = 0 ; i < agents.getLength(); i++)
            {
                Element el_agent = (Element)agents.item(i);
                yPos = Integer.parseInt(el_agent.getAttribute("Row"));
                xPos = Integer.parseInt(el_agent.getAttribute("Col"));
                id = Integer.parseInt(el_agent.getAttribute("Id"));
                coordinates.put(id, new Coordonnee(id,xPos,yPos));
            }
        }
        return coordinates;
    }

    /**
    *	\brief	Récupere un avatar à partir de la réponse du programme C++
    *   \param src Réponse du serveur C++
    *  \return Les coordonnées de l'avatar
    **/
    Coordonnee getAgent(InputSource src)
    {
        Document dom = generateDom(src);
        int xPos, yPos, id;
        Element agent = dom.getDocumentElement();

        // Si aucun agent n'a été ajouté
        if (!agent.getTagName().equals("Agent")) return new Coordonnee(-1,0,0);

        yPos = Integer.parseInt(agent.getAttribute("Row"));
        xPos = Integer.parseInt(agent.getAttribute("Col"));
        id = Integer.parseInt(agent.getAttribute("Id"));
        return new Coordonnee(id,xPos,yPos);
    }

    /**
    *	\brief	Récupere la map cognitive d'un avatar à partir du programme C++
    *   \param src Réponse du serveur C++
    *  \return La map cognitive
    **/
    CognitionMap getCognitionMap(InputSource src)
    {
        Document dom = generateDom(src);
        int yPos;
        int xPos;
        Element elXML = dom.getDocumentElement();
        CognitionMap map = new CognitionMap();

        map.setCoordSight(getPositions("Sight", elXML));
        map.setCoordPath(getPositions("Path", elXML));
        map.setCoordGhost(getPositions("Ghost", elXML));

        NodeList targetNodes = elXML.getElementsByTagName("Target");
        Element targetNode = (Element)targetNodes.item(0);
        yPos = Integer.parseInt(targetNode.getAttribute("Row"));
        xPos = Integer.parseInt(targetNode.getAttribute("Col"));
        map.setCoordTarget(new Coordonnee(0, xPos, yPos));

        return map;
    }

    /**
    *	\brief	Fonction de service pour cette classe - récupere les coordonnées d'une balise à partir d'un noeud
    *   \param name Le nom de la balise
    *   \param rootNode Le noeud à parser
    *  \return La liste des coordonnées
    **/
    private ArrayList<Coordonnee> getPositions(String name, Element rootNode)
    {
        int yPos;
        int xPos;
        ArrayList<Coordonnee> positions = new  ArrayList<Coordonnee>();

        NodeList nodeListOfGivenName = rootNode.getElementsByTagName(name);
        Element fatherNode = (Element)nodeListOfGivenName.item(0);

        NodeList positionNode = fatherNode.getElementsByTagName("Position");

        if(positionNode != null && positionNode.getLength() > 0)
        {
            for(int i = 0 ; i < positionNode.getLength(); i++)
            {
                Element el_pos = (Element)positionNode.item(i);
                yPos = Integer.parseInt(el_pos.getAttribute("Row"));
                xPos = Integer.parseInt(el_pos.getAttribute("Col"));
                positions.add(new Coordonnee(0, xPos, yPos));
            }
        }

        return positions;
    }

}
